/**
 * ============================================
 * 全局错误处理中间件模块
 *
 * 功能说明：
 * - 捕获和处理应用中抛出的所有错误
 * - 根据错误类型返回标准化的错误响应
 * - 记录详细的错误日志便于调试和监控
 * - 提供友好的错误信息给前端用户
 *
 * 错误处理原则：
 * - 不向客户端暴露敏感信息（如数据库结构、文件路径等）
 * - 统一的错误响应格式：{status: 1, msg: '错误描述', data: null}
 * - 根据错误类型设置合适的HTTP状态码
 * - 记录详细的错误信息用于问题排查
 *
 * 使用方式：
 * - 在app.js中作为最后一个中间件注册
 * - 会自动捕获所有同步和异步错误
 * ============================================
 */

/**
 * 全局错误处理中间件
 * 功能：统一处理应用中抛出的所有错误，返回标准化的错误响应
 * 特点：支持多种错误类型识别，提供友好的错误消息和合适的HTTP状态码
 *
 * @param {Error} err - 错误对象，包含错误信息和堆栈跟踪
 * @param {Object} req - Express请求对象，包含请求相关信息
 * @param {Object} res - Express响应对象，用于返回错误响应
 * @param {Function} next - Express下一个中间件函数（在此中间件中通常不使用）
 * @returns {void} 直接返回错误响应，不调用next()
 */
function errorHandler(err, req, res, next) {
  /**
   * 记录错误日志 - 便于问题排查和系统监控
   * 记录的信息包括：
   * - 错误消息和堆栈跟踪
   * - 请求的URL、方法和参数
   * - 时间戳用于追踪错误发生时间
   */
  console.error('❌ 错误详情:', {
    message: err.message,                    // 错误描述信息
    stack: err.stack,                        // 错误堆栈跟踪（开发环境有用）
    url: req.url,                            // 请求的URL路径
    method: req.method,                      // HTTP请求方法（GET/POST等）
    body: req.body,                          // 请求体数据（POST/PUT请求）
    query: req.query,                        // URL查询参数
    timestamp: new Date().toISOString()      // 错误发生时间（ISO格式）
  });

  /**
   * JWT认证错误处理
   * 场景：token签名无效、格式错误等
   * 响应：返回401未授权状态码，提示token无效
   */
  if (err.name === 'JsonWebTokenError') {
    return res.status(401).json({
      status: 1,              // 状态码1表示错误
      msg: '无效的认证令牌',    // 友好的错误提示
      data: null              // 错误时不返回数据
    });
  }

  /**
   * JWT令牌过期错误处理
   * 场景：token已超过有效期
   * 响应：返回401未授权状态码，提示token过期
   */
  if (err.name === 'TokenExpiredError') {
    return res.status(401).json({
      status: 1,
      msg: '认证令牌已过期',    // 提示用户重新登录获取新token
      data: null
    });
  }

  /**
   * 数据库唯一约束错误处理
   * 场景：插入或更新数据时违反唯一性约束（如重复的用户名、邮箱等）
   * 错误码：ER_DUP_ENTRY是MySQL的唯一约束错误码
   * 响应：返回200状态码但status为1，提示数据已存在
   */
  if (err.code === 'ER_DUP_ENTRY') {
    return res.json({
      status: 1,
      msg: '数据已存在',        // 提示用户数据重复
      data: null
    });
  }

  /**
   * 数据库连接错误处理
   * 场景：数据库服务不可用、连接超时等
   * 错误码：
   * - ECONNREFUSED: 连接被拒绝（数据库服务未启动）
   * - PROTOCOL_CONNECTION_LOST: 连接丢失（网络问题或数据库重启）
   * 响应：返回503服务不可用状态码，提示稍后重试
   */
  if (err.code === 'ECONNREFUSED' || err.code === 'PROTOCOL_CONNECTION_LOST') {
    return res.status(503).json({
      status: 1,
      msg: '数据库连接失败，请稍后重试',  // 提示系统暂时不可用
      data: null
    });
  }

  /**
   * 参数验证错误处理（express-validator）
   * 场景：请求参数不符合验证规则
   * 特征：err.errors是一个包含验证错误信息的数组
   * 响应：返回第一个验证错误的提示信息
   */
  if (err.errors && Array.isArray(err.errors)) {
    return res.json({
      status: 1,
      msg: err.errors[0]?.msg || '参数验证失败',  // 使用验证库提供的错误消息
      data: null
    });
  }

  /**
   * 默认错误处理
   * 功能：处理未被前面条件捕获的所有其他错误
   * 策略：
   * - 优先使用错误对象自带的statusCode或status
   * - 如果没有则使用500内部服务器错误
   * - 使用错误消息或默认消息
   */
  const statusCode = err.statusCode || err.status || 500;  // 获取HTTP状态码
  const message = err.message || '服务器内部错误';          // 获取错误消息

  // 返回标准化的错误响应
  res.status(statusCode).json({
    status: 1,
    msg: message,    // 错误描述信息
    data: null       // 错误时不返回业务数据
  });
}

/**
 * ====================
 * 模块导出
 * ====================
 * 功能：导出错误处理中间件供app.js使用
 * 注意：此中间件应该作为最后一个中间件注册
 */
module.exports = {
  errorHandler  // 全局错误处理中间件函数
};